package GMDPRE

type Poly struct {
	f [Threshold]BN
}

func (p *Poly) eval(fx *BN, sx *BN, rrm *BN, m *BN, mc DigT, digs int) {
	var x, tmp1, tmp2 BN
	var i int
	// sx enter mont area
	BnMontMul(&x, sx, rrm, m, mc, digs)
	//x = *sx
	tmp1 = x
	*fx = p.f[0]

	for i = 1; i < Threshold; i++ {
		BnMontMul(&tmp2, &tmp1, &p.f[i], m, mc, digs)
		BnModAdd(fx, &tmp2, fx, m, digs)
		BnMontMul(&tmp1, &tmp1, &x, m, mc, digs)
	}

	BnMontRdc(fx, fx, m, mc, digs)
}

// *********************************************************************************************************************
// ********************************************** Parting line *********************************************************
// *********************************************************************************************************************

const FragSize = Sm2CurveSize + Sm2CurveSize + Sm2AffPointSize

type Frag struct {
	id []uint8
	rk BN
	XA AffPoint
}

func (f *Frag) toBytes() []uint8 {
	var res = f.id
	res = append(res, BnToBytes(&f.rk, Sm2CurveDigit)...)
	res = append(res, AffP2Bytes(&f.XA)...)
	return res
}

func (f *Frag) fromBytes(fBytes []uint8) int {
	if len(fBytes) != FragSize {
		return -1
	}

	const idStart = 0
	const rkStart = idStart + Sm2CurveSize
	const XAStart = rkStart + Sm2CurveSize

	f.id = fBytes[idStart:rkStart]
	BytesToBn(&f.rk, Sm2CurveDigit, fBytes[rkStart:XAStart], Sm2CurveSize)
	Bytes2AffP(&f.XA, fBytes[XAStart:])
	return 0
}

func (f *Frag) GetId() []uint8 {
	return f.id
}

const CFragSize = Sm2AffPointSize + Sm2CurveSize + Sm2AffPointSize

type CFrag struct {
	E1 AffPoint
	id []uint8
	XA AffPoint
}

func (cf *CFrag) toBytes() []uint8 {
	var res = AffP2Bytes(&cf.E1)
	res = append(res, cf.id...)
	res = append(res, AffP2Bytes(&cf.XA)...)
	return res
}

func (cf *CFrag) fromBytes(cfBytes []uint8) int {
	if len(cfBytes) != CFragSize {
		return -1
	}
	const E1Start = 0
	const idStart = E1Start + Sm2AffPointSize
	const XAStart = idStart + Sm2CurveSize

	Bytes2AffP(&cf.E1, cfBytes[E1Start:idStart])
	cf.id = cfBytes[idStart:XAStart]
	Bytes2AffP(&cf.XA, cfBytes[XAStart:CFragSize])
	return 0
}

//*********************************************************************************************************************
//********************************************** Parting line *********************************************************
//*********************************************************************************************************************

const CapsuleSize = Sm2AffPointSize + Sm2AffPointSize

type Capsule struct {
	E AffPoint
	s []uint8
}

func (cap *Capsule) toBytes() []uint8 {
	var res = AffP2Bytes(&cap.E)
	res = append(res, cap.s...)
	return res
}

func (cap *Capsule) fromBytes(cBytes []uint8) int {
	if len(cBytes) != CapsuleSize {
		return -1
	}

	const EStart = 0
	const sStart = EStart + Sm2AffPointSize

	Bytes2AffP(&cap.E, cBytes[EStart:sStart])
	cap.s = cBytes[sStart:CapsuleSize]
	return 0
}

// Check 检验胶囊是否合法
func (cap *Capsule) Check(PubKeyBytes []uint8) bool {
	var ctx Sm3Ctx
	// tmp = H2(E)
	Sm3Init(&ctx)
	Sm3Update(&ctx, AffP2Bytes(&cap.E), Sm2AffPointSize)
	var tmp = Sm3Finish(&ctx) // 1次哈希

	return Sm2VrfHashSign(tmp, PubKeyBytes, cap.s) == 0
}
